////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_EXECUTE_ONCE_INL__
#define __WN_EXECUTE_ONCE_INL__

#include "WNCore/inc/WNBase.h"

#ifdef _WN_LINUX
    #include <pthread.h>
#else
    #include "WNCore/inc/WNAssert.h"
    #include "WNConcurrency/inc/WNThread.h"
    #include "WNConcurrency/inc/WNInterlocked.h"
#endif

__WN_INLINE WN_VOID WNExecuteOnce(WN_EXECUTE_ONCE_T* _control, WN_EXECUTE_ONCE_FUNCTION_T _function) {
    #ifdef _WN_LINUX
        pthread_once(_control, _function);
    #else
        while (WN_TRUE) {
            const WN_ATOM_T previous = WNInterlockedCompareSwap(_control, 1, 0);

            if (previous == 2) {
                return;
            } else if (previous == 0) {
                break;
            } else {
                WN_RELEASE_ASSERT(previous == 1);

                WNThreadYield();
            }
        }

        _function();

        WNInterlockedSwap(_control, 2);
    #endif
}

#endif // __WN_EXECUTE_ONCE_INL__